package com.skywo.demo1.service.impl

import com.skywo.demo1.common.exception.BusinessException
import com.skywo.demo1.common.result.ResultCode
import com.skywo.demo1.controller.req.UserAddReq
import com.skywo.demo1.controller.req.UserEditReq
import com.skywo.demo1.controller.req.UserQueryReq
import com.skywo.demo1.controller.req.UserRegisterReq
import com.skywo.demo1.controller.vo.UserInfoVo
import com.skywo.demo1.domain.UserDao
import com.skywo.demo1.reposity.UserInfo
import com.skywo.demo1.service.UserService
import org.slf4j.LoggerFactory
import org.springframework.data.domain.Page
import org.springframework.data.domain.PageImpl
import org.springframework.data.domain.PageRequest
import org.springframework.data.jpa.domain.Specification
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.core.userdetails.User
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import javax.persistence.criteria.Predicate
import javax.servlet.http.HttpServletRequest

@Service
class UserServiceImpl(
    private val userDao: UserDao
) : UserService {

    private val log = LoggerFactory.getLogger(this::class.java)

    override fun loadUserByUsername(username: String?): UserDetails {
        if (username.isNullOrEmpty()) {
            throw BusinessException("用户名不能为空")
        }
        val userInfo = userDao.findByUsername(username) ?: throw BusinessException("用户名不存在")
        return User(username, userInfo.password, emptyList())
    }

    override fun addUser(req: UserAddReq): Boolean {
        if (userDao.findByUsername(req.username) != null) {
            throw BusinessException(ResultCode.FAIL.code, "该用户名已存在")
        }
        val userInfo = UserInfo()
        userInfo.age = req.age
        userInfo.realName = req.realName
        userInfo.password = req.password
        userInfo.username = req.username
        userInfo.address = req.address
        userInfo.delFlag = 0
        userDao.save(userInfo)
        return true
    }

    override fun getLoginUser(request: HttpServletRequest): UserInfoVo {
        //获取到登录的用户名
        val authentication = SecurityContextHolder.getContext().authentication
        if (authentication.name.isNotEmpty()) {
            val userInfoVo = UserInfoVo()
            userInfoVo.username = authentication.name
            return userInfoVo
        } else {
            throw BusinessException(ResultCode.FAIL.code, "未登录")
        }
    }

    override fun userRegister(userRegisterReq: UserRegisterReq): Boolean {
        val userRepeat = userDao.findByUsername(userRegisterReq.username)
        if (userRepeat != null) {
            throw BusinessException(ResultCode.FAIL.code, "该用户名已存在")
        }
        if (userRegisterReq.password != userRegisterReq.checkPassword) {
            throw BusinessException(ResultCode.FAIL.code, "两次输入密码不一致")
        }
        val userInfo = UserInfo()
        userInfo.username = userRegisterReq.username
        userInfo.password = userRegisterReq.password
        userInfo.delFlag = 0
        userDao.save(userInfo)
        return true
    }

    override fun getUserById(id: String): UserInfoVo {
        val userInfo =
            userDao.findById(id.toLong()).orElseThrow { BusinessException(ResultCode.FAIL.code, "用户不存在") }
        val userInfoVo = UserInfoVo()
        userInfoVo.age = userInfo.age
        userInfoVo.id = userInfo.id.toString()
        userInfoVo.realName = userInfo.realName
        userInfoVo.username = userInfo.username
        userInfoVo.address = userInfo.address
        return userInfoVo
    }

    fun updateById(userInfo: UserInfo): Boolean {
        userDao.findById(userInfo.id!!)
            .map { existingUser ->
                existingUser.apply {
                    if (userInfo.username != null) {
                        username = userInfo.username
                    }
                    if (userInfo.password != null) {
                        password = userInfo.password
                    }
                    if (userInfo.realName != null) {
                        realName = userInfo.realName
                    }
                    if (userInfo.address != null) {
                        address = userInfo.address
                    }
                    if (userInfo.age != null) {
                        age = userInfo.age
                    }
                }
                userDao.save(existingUser)
            }
            .orElseThrow({ BusinessException(ResultCode.FAIL.code, "更新失败") })
        return true
    }

    @Transactional(rollbackFor = [Throwable::class])
    override fun editUser(req: UserEditReq): Boolean {
        req.id.ifBlank { throw BusinessException(ResultCode.PARAM_ERROR.code, "id不能为空") }
        val userInfo = UserInfo()
        userInfo.id = req.id.toLong()
        userInfo.username = req.username
        if (!req.username.isNullOrEmpty()) {
            val userRepeat = userDao.findByUsername(req.username!!)
            if (userRepeat != null && req.id.toLong() != userRepeat.id) {
                throw BusinessException(ResultCode.FAIL.code, "该用户名已存在")
            }
        }
        userInfo.password = req.password
        userInfo.realName = req.realName
        userInfo.address = req.address
        userInfo.age = req.age
        return this.updateById(userInfo)
    }

    override fun removeUser(id: String): Boolean {
        userDao.deleteById(id.toLong())
        return true
    }

    override fun pageUser(userQueryReq: UserQueryReq, pageNum: Int, pageSize: Int): Page<UserInfoVo> {
        val pageable = PageRequest.of(pageNum - 1, pageSize)
        val spec = Specification<UserInfo> { root, _, cb ->
            val predicates = mutableListOf<Predicate>()

            userQueryReq.realName?.let {
                if (it.isBlank()) {
                    return@let
                }
                predicates.add(cb.like(root.get("realName"), "%$it%"))
            }

            userQueryReq.age?.let {
                predicates.add(cb.equal(root.get<Int>("age"), it))
            }

            userQueryReq.address?.let {
                if (it.isBlank()) {
                    return@let
                }
                predicates.add(cb.like(root.get("address"), "%$it%"))
            }

            cb.and(*predicates.toTypedArray())
        }
        val pageInfo = userDao.findAll(spec, pageable)
        val content = pageInfo.content.map { userInfo ->
            UserInfoVo().apply {
                id = userInfo.id.toString()
                username = userInfo.username
                realName = userInfo.realName
                age = userInfo.age
                address = userInfo.address
            }
        }
        return PageImpl(content, pageable, pageInfo.totalElements)
    }

    @Transactional(rollbackFor = [Throwable::class])
    override fun removeUserList(ids: List<String>): Boolean {
        val idList: List<Long> = ids.map { id -> id.toLong() }.toList()
        userDao.deleteAllById(idList)
//        ids.forEach { id ->
//            run {
//                userDao.deleteById(id.toLong())
//            }
//        }
        return true
    }
}